package com.swinw.asumall.search.service.impl;

import com.alibaba.fastjson.JSON;
import com.swinw.asumall.search.constant.EsConstant;
import com.swinw.asumall.search.service.SearchService;
import com.swinw.asumall.search.vo.SearchResult;
import com.swinw.asumall.search.vo.SearchVo;
import com.swinw.common.to.SkuEsModel;
import org.apache.commons.lang.StringUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.ParsedNested;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    @Override
    public SearchResult search(SearchVo searchVo) {
        //1、构建出查询需要的DSL语句
        SearchResult result = null;
        //2、准备检索请求
        SearchRequest searchRequest = buildSearchRequest(searchVo);

        try{
            SearchResponse search = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            result = buildSearchResponse(search,searchVo);
        }catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 准备检索请求
     * @return
     */
    private SearchRequest buildSearchRequest(SearchVo searchVo) {
        String[] strings = {EsConstant.ES_INDEX};
        //1、构建DSL语句
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        /**
         * 查询：
         *  模糊匹配，过滤（按照属性、分类、品牌、价格区间、库存）
         */
        //TODO 1、构建BoolQuery
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //1.1、构建must
        if(!StringUtils.isEmpty(searchVo.getKeyword())){
            //must的模糊匹配
            boolQuery.must(QueryBuilders.matchQuery("skuTitle",searchVo.getKeyword()));
        }
        sourceBuilder.query(boolQuery);
        //1.2、构建Filter
        if(searchVo.getCatalog3Id() != null){
            //按照三级分类ID查询
            boolQuery.filter(QueryBuilders.termQuery("catalogId",searchVo.getCatalog3Id()));
        }
        if(searchVo.getBrandId() != null && searchVo.getBrandId().size() > 0){
            //按照品牌ID查询
            boolQuery.filter(QueryBuilders.termsQuery("brandId",searchVo.getBrandId()));
        }
        if(searchVo.getHasStock() != null){
            boolQuery.filter(QueryBuilders.termsQuery("hasStock",searchVo.getHasStock() == 1));
        }
//        if(searchVo.getHasStock() == 0){
//            //没有库存
//        }else{
//            //有库存
//            boolQuery.filter(QueryBuilders.termsQuery("hasStock",true));
//        }

        if(searchVo.getAttrs() != null && searchVo.getAttrs().size() > 0){
            //通过属性查询
            searchVo.getAttrs().forEach(attr->{
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                //检索条件
                String[] split = attr.split("_");
                String attrId = split[0]; //检索的属性id
                String[] attrValues = split[1].split(":");//检索的属性值
                boolQueryBuilder.must(QueryBuilders.termQuery("attrs.attrId",attrId));
                boolQueryBuilder.must(QueryBuilders.termsQuery("attrs.attrValue",attrValues));
                NestedQueryBuilder attrQuery = QueryBuilders.nestedQuery("attrs", boolQueryBuilder, ScoreMode.None);
                boolQuery.filter(attrQuery);
            });
        }

        if(!StringUtils.isEmpty(searchVo.getSkuPrice())){
            //按照价格区间进行查询 1_500、_500、500_
            String[] s = searchVo.getSkuPrice().split("_");
            RangeQueryBuilder skuPrice = QueryBuilders.rangeQuery("skuPrice");
            if(s.length == 2){//1_500
                skuPrice.gte(s[0]).lte(s[1]);
            }else if(s.length == 1){
                if(searchVo.getSkuPrice().startsWith("_")){//如果是也“_”开头 _500
                    skuPrice.lte(s[0]);
                }else{//500_
                    skuPrice.gte(s[0]);
                }
            }
            boolQuery.filter(skuPrice);
        }
        //查询条件结束
        sourceBuilder.query(boolQuery);

        //TODO 2、排序
        if(!StringUtils.isEmpty(searchVo.getSort())){
            String[] split = searchVo.getSort().split("_");
            SortOrder sortOrder = split[1].equalsIgnoreCase("asc") ? SortOrder.ASC : SortOrder.DESC;
            sourceBuilder.sort(split[0],sortOrder);
        }

        //TODO 3、分页
        sourceBuilder.from((searchVo.getPageNum()-1)*EsConstant.PRODUCT_PAGESIZE);
        sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);

        //TODO 4、高亮
        if(!StringUtils.isEmpty(searchVo.getKeyword())){
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("skuTitle");
            highlightBuilder.preTags("<b style='color:red'>");
            highlightBuilder.postTags("</b>");
            sourceBuilder.highlighter(highlightBuilder);
        }

        //TODO 5、聚合分析
        //TODO 5.1、品牌聚合
        TermsAggregationBuilder brandAgg = AggregationBuilders.terms("brand_agg");
        brandAgg.field("brandId").size(50);
        //子聚合:品牌名和品牌图片
        brandAgg.subAggregation(AggregationBuilders.terms("brand_name_agg").field("brandName").size(1));
        brandAgg.subAggregation(AggregationBuilders.terms("brand_img_agg").field("brandImg").size(1));
        sourceBuilder.aggregation(brandAgg);

        //TODO 5.2、分类聚合
        TermsAggregationBuilder catalogAgg = AggregationBuilders.terms("catalog_agg");
        catalogAgg.field("catalogId");
        catalogAgg.size(20);
        //子聚合
        catalogAgg.subAggregation(AggregationBuilders.terms("catalog_name_agg").field("catalogName").size(1));
        sourceBuilder.aggregation(catalogAgg);

        //TODO 5.3、属性聚合
        NestedAggregationBuilder nested = AggregationBuilders.nested("attr_agg", "attrs");
        //聚合所有的AttrId
        TermsAggregationBuilder attr_id_agg = AggregationBuilders.terms("attr_id_agg").field("attrs.attrId");
        //聚合当前attrId的attrName
        TermsAggregationBuilder attr_name_agg = AggregationBuilders.terms("attr_name_agg").field("attrs.attrName").size(1);
        //聚合当前attrName的所有可能attrValue
        TermsAggregationBuilder attr_value_agg = AggregationBuilders.terms("attr_value_agg").field("attrs.attrValue").size(50);
        attr_id_agg.subAggregation(attr_name_agg);
        attr_id_agg.subAggregation(attr_value_agg);
        nested.subAggregation(attr_id_agg);
        sourceBuilder.aggregation(nested);

        System.out.println("构建DSL语句 " + sourceBuilder.toString());
        SearchRequest searchRequest = new SearchRequest(strings,sourceBuilder);

        return searchRequest;
    }

    /**
     * 封装结果
     * @param search
     * @return
     */
    private SearchResult buildSearchResponse(SearchResponse search,SearchVo searchVo) {
        SearchHits hits = search.getHits();
        SearchResult searchResult = new SearchResult();
        //1、封装返回的所有商品
        SearchHit[] product = hits.getHits();
        ArrayList<SkuEsModel> modelArrayList = new ArrayList<SkuEsModel>();
        if(product != null && product.length > 1){
            for(SearchHit item : product){
                String sourceAsString = item.getSourceAsString();
                SkuEsModel skuEsModel = JSON.parseObject(sourceAsString, SkuEsModel.class);
                if(!StringUtils.isEmpty(searchVo.getKeyword())){
                    skuEsModel.setSkuTitle(item.getHighlightFields().get("skuTitle").getFragments()[0].toString());
                }
                modelArrayList.add(skuEsModel);
            }
        }
        searchResult.setProducts(modelArrayList);
        //2、当前商品涉及到的所有属性信息
        ParsedNested attrAgg = search.getAggregations().get("attr_agg");
        List<SearchResult.AttrVo> attrVoList = new ArrayList<>();
        ParsedLongTerms attrIdAgg = attrAgg.getAggregations().get("attr_id_agg");
        List<? extends Terms.Bucket> attrAggBuckets = attrIdAgg.getBuckets();
        if(attrAggBuckets != null && attrAggBuckets.size() > 0){
            attrAggBuckets.forEach(item->{
                SearchResult.AttrVo attrVo = new SearchResult.AttrVo();
                attrVo.setAttrId(Long.parseLong(item.getKeyAsString()));
                //封装属性名
                ParsedStringTerms attrNameAgg = item.getAggregations().get("attr_name_agg");
                String attrNameString = attrNameAgg.getBuckets().get(0).getKeyAsString();
                attrVo.setAttrName(attrNameString);
                //封装属性值
                ArrayList<String> attrValueList = new ArrayList<>();
                ParsedStringTerms attrValueAgg = item.getAggregations().get("attr_value_agg");
                List<? extends Terms.Bucket> valueAggBuckets = attrValueAgg.getBuckets();
                if(valueAggBuckets != null && valueAggBuckets.size() > 0){
                    valueAggBuckets.forEach(elem->{
                        String attrValue = elem.getKeyAsString();
                        attrValueList.add(attrValue);
                    });
                }
                attrVo.setAttrValue(attrValueList);
                attrVoList.add(attrVo);
            });
        }
        searchResult.setAttrs(attrVoList);
        //3、当前商品涉及的品牌信息
        ParsedLongTerms brandAgg = search.getAggregations().get("brand_agg");
        List<SearchResult.BrandVO> brandVOList = new ArrayList<>();
        List<? extends Terms.Bucket> brandAggBuckets = brandAgg.getBuckets();
        if(brandAggBuckets != null && brandAggBuckets.size() > 0){
            brandAggBuckets.forEach(item->{
                SearchResult.BrandVO brandVO = new SearchResult.BrandVO();
                String keyAsString = item.getKeyAsString();
                brandVO.setBrandId(Long.parseLong(keyAsString));
                //获取子聚合中品牌的图片
                ParsedStringTerms brandImgAgg = item.getAggregations().get("brand_img_agg");
                String brandImg = brandImgAgg.getBuckets().get(0).getKeyAsString();
                brandVO.setBrandImg(brandImg);
                //获取子聚合中品牌的名字
                ParsedStringTerms brandNameAgg = item.getAggregations().get("brand_name_agg");
                String brandName = brandNameAgg.getBuckets().get(0).getKeyAsString();
                brandVO.setBrandName(brandName);
                brandVOList.add(brandVO);
            });
        }
        searchResult.setBrands(brandVOList);
        //4、当前商品涉及的分类信息
        ParsedLongTerms catalogAgg = search.getAggregations().get("catalog_agg");
        List<? extends Terms.Bucket> buckets = catalogAgg.getBuckets();
        List<SearchResult.CatalogVo> catalogVoList = new ArrayList<>();
        if(buckets != null && buckets.size() > 0){
            buckets.forEach(item->{
                SearchResult.CatalogVo catalogVo = new SearchResult.CatalogVo();
                String keyAsString = item.getKeyAsString();
                catalogVo.setCatalogId(Long.parseLong(keyAsString));
                //获取子聚合中商品的的名字
                ParsedStringTerms catalogNameAgg = item.getAggregations().get("catalog_name_agg");
                String catalogName = catalogNameAgg.getBuckets().get(0).getKeyAsString();
                catalogVo.setCatalogName(catalogName);
                catalogVoList.add(catalogVo);
            });
        }
        searchResult.setCatalogs(catalogVoList);
        //5、分页信息
        //5.1、分页信息
        searchResult.setPageNum(searchVo.getPageNum());
        //5.2、总记录数量
        long total = hits.getTotalHits().value;
        searchResult.setTotal(total);
        //5.3、总页码
        searchResult.setTotalPages((int) ((total - 1)/EsConstant.PRODUCT_PAGESIZE + 1));
        List<Integer> pageList = new ArrayList<>();
        for(int i = 1; i <= searchResult.getTotalPages(); i++){
            pageList.add(i);
        }
        searchResult.setPageList(pageList);
        return searchResult;
    }
}
